/**
 * 抖音关注：程序员三丙
 * 知识星球：https://t.zsxq.com/j9b21
 */
package sanbing.example.dylike.application.config;

import com.google.common.base.Stopwatch;
import io.micrometer.core.instrument.Timer;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import sanbing.example.dylike.util.DefaultCounter;
import sanbing.example.dylike.util.StatsFactory;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
@Aspect
@Slf4j
public class MethodPerformanceAspect {

    @Resource
    StatsFactory statsFactory;

    private final Map<String, Timer> TIMER_MAP = new ConcurrentHashMap<>();
    private final Map<String, DefaultCounter> COUNTER_MAP = new ConcurrentHashMap<>();

    @Pointcut("execution(* sanbing.example..*.*Service.*(..)) || execution(* sanbing.example..*.*Controller.*(..))")
    private void pointCut() {
    }

    @Around("pointCut()")
    public Object timing(ProceedingJoinPoint joinPoint) throws Throwable {
        Stopwatch stopwatch = Stopwatch.createStarted();
        try {
            return joinPoint.proceed();
        } finally {
            String className = joinPoint.getSignature().getDeclaringType().getName();
            String method = className.substring(className.lastIndexOf(".") + 1) + "." + joinPoint.getSignature().getName();

            TIMER_MAP.computeIfAbsent(method, k -> statsFactory.createTimer("method_invoke_latency", "method", k))
                    .record(stopwatch.elapsed());

            COUNTER_MAP.computeIfAbsent(method, k -> statsFactory.createDefaultCounter("method_invoke_counter", "method", k))
                    .increment();

        }
    }
}
